package org.shejko.util.splitunite;

import java.util.Collection;
import java.util.Iterator;

/**
 * A simple (direct) implementation of {@code ISplitUnite} interface.
 * 
 * @author dmytros
 */
public class DirectSplitUnite implements ISplitUnite
{
    private final char sep_, esc_;

    public DirectSplitUnite(char sep, char esc)
    {
        if (sep == esc)
        {
            throw new IllegalArgumentException(String.format("sep == esc == \\u%04x (%c)", (int) sep, sep));
        }
        sep_ = sep;
        esc_ = esc;
    }

    @Override
    public void split(String str, Collection<String> col)
    {
        StringBuilder tmp = new StringBuilder();
        boolean allEmpty = true;
        int l = str.length(), f = 0, n, m;
        for (; (n = str.indexOf(sep_, f)) >= 0; f = m + 1)
        {
            m = extend(str, n, l);
            int d = m - n;
            int h = n + d / 2;
            String part = str.substring(f, h);
            if ((d & 1) == 0)
            {
                String item = appendAndResetBuffer(tmp, part);
                allEmpty &= item.isEmpty();
                col.add(item);
            }
            else
            {
                tmp.append(part);
                tmp.append(sep_);
            }
        }
        {
            String item = appendAndResetBuffer(tmp, str.substring(f));
            allEmpty &= item.isEmpty();
            if (!allEmpty)
            {
                col.add(item);
            }
        }
    }

    String appendAndResetBuffer(StringBuilder tmp, String str)
    {
        if (tmp.length() > 0)
        {
            str = tmp.append(str).toString();
            tmp.setLength(0);
        }
        return str;
    }

    @Override
    public void unite(Iterable<String> col, StringBuilder builder)
    {
        Iterator<String> iter = col.iterator();
        boolean hasMore = iter.hasNext();
        boolean allEmpty = hasMore;
        while (hasMore)
        {
            String item = iter.next();
            hasMore = iter.hasNext();
            allEmpty &= appendForUnite(builder, item, hasMore);
        }
        if (allEmpty)
        {
            builder.append(sep_);
        }
    }

    boolean appendForUnite(StringBuilder builder, String item, boolean hasMore)
    {
        int l = item.length(), f = 0, n;
        for (; (n = item.indexOf(sep_, f)) >= 0; f = n + 1)
        {
            int m = extend(item, n, l);
            // abc;!!!
            // ^  ^  ^
            // |  |  |
            // f  n  m
            builder.append(item.substring(f, n));
            builder.append(esc_);
            builder.append(item.substring(m, n + 1));
            // abc!!! ! !!!;
        }
        n = item.length();
        builder.append(item.substring(f));
        if (hasMore) {
            int m = extend(item, n, l);
            // abc!!!
            // ^  ^  ^
            // |  |  |
            // f  m  n
            builder.append(item.substring(m));
            // abc!!! !!!
            builder.append(sep_);
        }
        return item.isEmpty();
    }

    int extend(String item, int n, int l)
    {
        int m = n + 1;
        while (m <= l && item.charAt(m) == esc_) ++m;
        return m - 1;
    }

}
